<template>
    <div class="container" ref="container"></div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from "vue";
import * as THREE from "three";
import carImg from "./images/car.png";

// 渲染器
let renderer: THREE.WebGLRenderer;
// 场景
let scene: THREE.Scene;
// 汽车模型
let carMesh: THREE.Mesh;
// 相机
let camera: THREE.PerspectiveCamera;
// 容器
let container = ref<HTMLElement>();

onMounted(init);

async function init() {
    // 屏幕宽高
    let w = container.value.clientWidth;
    let h = container.value.clientHeight;
    // 渲染器
    renderer = new THREE.WebGLRenderer();
    renderer.setSize(w, h);
    container.value.appendChild(renderer.domElement);
    // 场景
    scene = new THREE.Scene();
    // 加载纹理图
    let texture = await new Promise<THREE.Texture>((resolve) => {
        new THREE.TextureLoader().load(carImg, (texture) => {
            resolve(texture);
        });
    });
    // 材质和形状
    let material = new THREE.MeshBasicMaterial({ map: texture, side: THREE.BackSide });
    let geometry = new THREE.SphereGeometry(100, 500, 500);
    // 创建汽车模型
    carMesh = new THREE.Mesh(geometry, material);
    carMesh.rotation.y = Math.PI / 2;
    carMesh.rotation.x = Math.PI / 20;
    scene.add(carMesh);

    // 相机
    camera = new THREE.PerspectiveCamera(60, w / h);
    camera.position.set(0, 0, 20);

    // 渲染界面
    renderer.render(scene, camera);
    // 添加事件
    addEvent();
}

function addEvent() {
    // 按下时的鼠标坐标
    let lastX: number = null,
        lastY: number = null;
    // 按下时鼠标最后移动的距离和时间戳
    let moveX = 0,
        moveY = 0;
    let moveTime = 0;
    // 移动定时器
    let moveTimer = 0;

    // 鼠标按下事件
    renderer.domElement.onmousedown = function (e) {
        lastX = e.clientX;
        lastY = e.clientY;
        // 取消移动定时器
        cancelAnimationFrame(moveTimer);
        // 鼠标移动事件
        this.onmousemove = function (e) {
            moveX = e.clientX - lastX;
            moveY = e.clientY - lastY;
            lastX = e.clientX;
            lastY = e.clientY;
            moveTime = Date.now();
            moveRender(moveX, moveY);
        };
    };
    // 释放鼠标事件
    renderer.domElement.onmouseup = function (e) {
        // 清空移动事件
        this.onmousemove = null;
        // 距离上次移动100ms内，开启移动惯性
        if (Date.now() - moveTime < 100) {
            moveTimer = requestAnimationFrame(moveInertia);
        }
    };
    // 移动惯性
    function moveInertia() {
        moveX *= 0.9;
        moveY *= 0.9;
        moveRender(moveX, moveY);
        // 惯性到0.1停止
        if (Math.abs(moveX) < 0.1 && Math.abs(moveY) < 0.1) return;
        moveTimer = requestAnimationFrame(moveInertia);
    }
    // 移动渲染
    function moveRender(moveX: number, moveY: number) {
        let roX = carMesh.rotation.x - moveY * 0.0015;
        let roY = carMesh.rotation.y - moveX * 0.0015;
        // 限制x方向旋转角度不能超过1/4圆
        carMesh.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, roX));
        carMesh.rotation.y = Math.max(roY);
        // 渲染
        renderer.clear();
        renderer.render(scene, camera);
    }
    // 滚轮滚动事件
    renderer.domElement.onwheel = function (e) {
        // 调整相机Z轴位置
        let z = camera.position.z + e.deltaY / 50;
        camera.position.z = Math.max(-20, Math.min(60, z));
        // 渲染
        renderer.clear();
        renderer.render(scene, camera);
    };

    // 自动移动
    function moveAuto() {
        // 触发过鼠标按下事件，则停止自动移动
        if (lastX != null) {
            return;
        }
        // 旋转y轴并渲染
        carMesh.rotation.y += 0.0005;
        renderer.clear();
        renderer.render(scene, camera);
        // 递归调用
        requestAnimationFrame(moveAuto);
    }
    moveAuto();
}
</script>
<style scoped lang="scss">
.container {
    height: 100%;
}
</style>
